//
//  WechatManager.swift
//  WechatSDK-Swift
//
//  Created by xyanl on 2023/12/6.
//


/**
 集成步骤
 1.通过 CocoaPods 集成
 
 pod 'WechatOpenSDK-XCFramework'
 
 保存并执行 pod install,然后用后缀为.xcworkspace 的文件打开工程。
 
 注意:
 
 命令行下执行 pod search WechatOpenSDK-XCFramework,如显示的 WechatOpenSDK-XCFramework 版本不是最新的，则先执行 pod repo update 操作更新本地 repo 的内容
 2. 在 Xcode 中，选择你的工程设置项，选中“TARGETS”一栏，在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序 id（如下图所示）。
 
 3. 在Xcode中，选择你的工程设置项，选中“TARGETS”一栏，在 “info”标签栏的“LSApplicationQueriesSchemes“添加weixin、weixinULAPI、weixinURLParamsAPI（如下图所示）。
 
 经验证，在iOS 15系统上，使用Xcode 13编译出的App，LSApplicationQueriesSchemes的数量会限制为50个。第50个之后的scheme配置会不生效，需要确保"weixin"、"weixinULAPI"和"weixinURLParamsAPI"配置在LSApplicationQueriesSchemes的前50个。
 
 4. 在你的工程文件中选择 Build Setting，在"Other Linker Flags"中加入"-ObjC -all_load"。
 
 (注：请使用 xCode4.5 及以上版本)
 
 */

/**
 iOS 微信App授权登录/网页版授权登录（swift）
 https://zhuanlan.zhihu.com/p/435945791?utm_id=0
 
 
 */


import UIKit
import SwiftyUserDefaults

enum WechatResp {
    case login
    case userInfo
}

/// 请求发送场景
enum WechatScene: Int {
    /// 聊天界面
    case session = 0
    /// 朋友圈
    case timeline
    /// 收藏
    case favorite
    /// 指定联系人
    case specifiedSession
    /// 状态
    case state
}

@objc enum WechatResultCode: Int32 {
    /// 成功
    case success     = 0
    /// 普通错误类型
    case common      = -1
    /// 用户点击取消并返回
    case cancel      = -2
    /// 发送失败
    case fail        = -3
    /// 授权失败
    case deny        = -4
    /// 微信不支持
    case unsupport   = -5
}


@objc protocol WechatManagerDelegate: NSObjectProtocol {
    
    /// 授权登录
    /// - Parameters:
    ///   - code: 用户换取 access_token 的 code，仅在 ErrCode 为 0 时有效
    ///   - errCode: 错误码
    @objc optional func wechatAuthResp(code: String?, errCode: WechatResultCode)
    
    @objc optional func wechatPayResp(code: WechatResultCode, errMsg: String)
    
    /// 分享回调
    @objc optional func wechatShareResp()
}

enum WechatManagerError: Error {
    case faile
    case invalid
    case other
}

class WechatManager: NSObject {
    
    // MARK: - 用于初始化，必填的3个属性
    /// 应用唯一标识，在微信开放平台提交应用审核通过后获得
    public var appID: String!
    /// 微信开放平台，注册的应用程序AppSecret
    public var appSecret: String!
    /// 微信开放平台，注册的应用程序所对应的 Universal Links
    public var universalLink: String!
    /// 用于保持请求和回调的状态，授权请求后原样带回给第三方
    public var state: String!
    
    public static let shared = WechatManager()
    
    weak var delegate: WechatManagerDelegate?
    
    /// 用于接收和处理来自第三方的请求的闭包
    public typealias Handle = (Result<[String: Any], WechatManagerError>) -> Void
    /// 用于接收和处理来自微信的请求的闭包
    var completionHandler: Handle!
    
    /// 授权登录后返回的
    public var openid: String! {
        get {
            Defaults[\.wxOpenid]
        }
        set {
            Defaults[\.wxOpenid] = newValue
        }
    }
    /// 授权登录后返回的
    public var unionid: String! {
        get {
            Defaults[\.wxUnionid]
        }
        set {
            Defaults[\.wxUnionid] = newValue
        }
    }
    
    /// 调用授权关系接口的调用凭证
    public var accessToken: String! {
        get {
            Defaults[\.wxAccessToken]
        }
        set {
            Defaults[\.wxAccessToken] = newValue
        }
    }
    
    /// 用户刷新 access_token
    public var refreshToken: String! {
        get {
            Defaults[\.wxRefreshToken]
        }
        set {
            Defaults[\.wxRefreshToken] = newValue
        }
    }
    
}

// MARK: - WXApi func
extension WechatManager {
    
    public func startLog(by level: WXLogLevel) {
        WXApi.startLog(by: level, logBlock: { log in
            xLog("[微信] 日志: \(log)")
        })
    }
    
    /// 注册
    /// - Returns: description
    @discardableResult
    public static func registerApp() -> Bool {
        
        // WechatManager.shared.startLog(by: .detail)
        
        let isSuccess = WXApi.registerApp(WechatManager.shared.appID, universalLink: WechatManager.shared.universalLink)
        
        //        WXApi.checkUniversalLinkReady { step, result in
        //            xLog("[微信] 自查 step:\(step.rawValue), success:\(result.success), errorInfo:\(result.errorInfo), 建议:\(result.suggestion)")
        //        }
        
        return isSuccess
    }
    
    /// 检查是否已安装微信
    /// - Returns: 微信已安装返回true，未安装返回false
    public static func isInstalled() -> Bool {
        return WXApi.isWXAppInstalled()
    }
    
    /// 处理微信通过URL启动App时传递的数据
    /// 需要在 application:openURL:sourceApplication:annotation: 或者 application:handleOpenURL中调用。
    /// - Parameter url: 微信启动第三方应用时传递过来的URL
    /// - Returns: 成功返回true，失败返回false
    @discardableResult
    public func handleOpenURL(_ url: URL) -> Bool {
        return WXApi.handleOpen(url, delegate: self)
    }
    
    /// 处理微信通过Universal Link启动App时传递的数据
    /// 需要在 application:continueUserActivity:restorationHandler:中调用。
    /// - Parameter userActivity: 微信启动第三方应用时系统API传递过来的userActivity
    /// - Returns: 成功返回YES，失败返回NO。
    @discardableResult
    public func handleOpenUniversalLink(userActivity: NSUserActivity) -> Bool {
        return WXApi.handleOpenUniversalLink(userActivity, delegate: self)
    }
}

extension WechatManager {
    /// 微信登录
    fileprivate func login() {
        xLog("[微信] 授权登录")
        let req = SendAuthReq()
        // 只能填 snsapi_userinfo
        req.scope = "snsapi_userinfo"
        req.state = WechatManager.shared.state
        
        //第三方向微信终端发送一个SendAuthReq消息结构
        WXApi.send(req)
    }
    
    /// 退出登录
    public static func logout() {
        WechatManager.shared.openid = ""
        WechatManager.shared.unionid = ""
        WechatManager.shared.accessToken = ""
        WechatManager.shared.refreshToken = ""
        xLog("[微信] 清空授权信息")
    }
    
    /// 检查微信授权登录，已经授权过，检查token的有效期，
    /// - Parameter completionHandler: 取得的token信息
    public func checkAuth(_ completionHandler: @escaping Handle) {
        self.completionHandler = completionHandler
        if self.accessToken != nil {
            self.checkToken()
        } else {
            self.login()
        }
    }
    
    /// 获取调用凭证
    /// - Parameter code: 微信授权登录返回的 code
    public func getAccessToken(_ code: String) {
        AlamofireController.request(WechatRoute.accessToken(code)) { result in
            xLog("[微信] 获取调用凭证: \(result)")
            if result["errcode"] is Int32 {
                self.completionHandler(.failure(.faile))
                return
            }
            self.saveOpenId(result)
        }
    }
    
    
    /// 检查 AccessToken 是否过期
    fileprivate func checkToken() {
        AlamofireController.request(WechatRoute.checkToken) { result in
            xLog("[微信] 检查 AccessToken 是否过期: \(result)")
            // token 还有效
            if let errcode = result["errcode"] as? Int32, errcode == 0 {
                self.completionHandler(.success(result))
                return
            }
            
            // token 还失效，刷新
            self.refreshAccessToken()
        }
    }
    
    
    /// 刷新、续期 AccessToken
    fileprivate func refreshAccessToken() {
        
        AlamofireController.request(WechatRoute.refreshToken) { result in
            xLog("[微信] 刷新、续期 AccessToken: \(result)")
            // 接口报错的时候，不包含 errcode
            if !result.keys.contains("errcode") {
                self.saveOpenId(result)
            } else {
                // 刷新token失败，重新授权登录
                self.login()
            }
        }
    }
    
    fileprivate func saveOpenId(_ info: [String: Any]) {
        self.openid = info["openid"] as? String
        self.unionid = info["unionid"] as? String
        self.accessToken = info["access_token"] as? String
        self.refreshToken = info["refresh_token"] as? String
        self.completionHandler(.success(["errcode": 0, "errmsg": "saveOpenId ok"]))
    }
    
    /// 获取微信用户基本信息
    /// - Parameter completionHandler: 微信基本用户信息
    public func getUserInfo (_ completionHandler: @escaping Handle) {
        self.completionHandler = completionHandler
        
        AlamofireController.request(WechatRoute.userinfo) { result in
            xLog("[微信] 微信用户基本信息: \(result)")
            if result["errcode"] is Int32 {
                completionHandler(.failure(.faile))
                return
            }
            
            self.completionHandler(.success(result))
        }
    }
}

// MARK: - 分享
extension WechatManager {
    
    /// 分享文本消息
    /// - Parameters:
    ///   - scence: 请求发送场景
    ///   - text: 文本消息内容
    public static func shareText(
        _ scence: WechatScene,
        text: String
    ) {
        let req = SendMessageToWXReq()
        req.bText = true
        req.scene = Int32(scence.rawValue)
        req.text = text
        WXApi.send(req)
    }
    
    
    /// 分享图片
    /// - Parameters:
    ///   - scence: 请求发送场景
    ///   - image: 图片真实数据内容，大小不能超过25M
    public static func shareImage(
        _ scence: WechatScene,
        image: UIImage
    ) {
        
        let object = WXImageObject()
        object.imageData = image.pngData()!
        
        let message = WXMediaMessage()
        message.mediaObject = object
        /// 缩略图数据,大小不能超过256K
        message.setThumbImage(UIImage(data: image.compress(maxSize: 256*1024)!)!)
        sendMediaMessage(scence: scence, message: message)
    }
    
    
    /// 分享超链接
    /// - Parameters:
    ///   - scence: 请求发送场景
    ///   - title: 标题
    ///   - description: 描述内容
    ///   - thumbImage: 缩略图
    ///   - url: 地址
    public static func shareWebpageUrl(
        _ scence: WechatScene,
        title: String,
        description: String,
        thumbImage: UIImage? = nil,
        url: String
    ) {
        let object = WXWebpageObject()
        object.webpageUrl = url
        
        let message = getMediaMesage(title: title, description: description, thumbImage: thumbImage)
        message.mediaObject = object
        sendMediaMessage(scence: scence, message: message)
    }
    
    
    /// 分享音乐
    /// - Parameters:
    ///   - scence: 请求发送场景
    ///   - title: 标题
    ///   - description: 描述内容
    ///   - thumbImage: 缩略图
    ///   - musicUrl: 音乐网页的url地址，长度不能超过10K。
    ///   - dataUrl: 音乐数据url地址，长度不能超过10K。
    public static func shareMusic(
        _ scence: WechatScene,
        title: String,
        description: String,
        thumbImage: UIImage? = nil,
        musicUrl: String,
        dataUrl: String
    ) {
        let object = WXMusicObject()
        object.musicUrl = musicUrl
        object.musicDataUrl = dataUrl
        
        let message = getMediaMesage(title: "", description: "", thumbImage: thumbImage)
        message.mediaObject = object
        sendMediaMessage(scence: scence, message: message)
    }
    
    /// 分享视频
    /// - Parameters:
    ///   - scence: 请求发送场景
    ///   - title: 标题
    ///   - description: 描述内容
    ///   - thumbImage: 缩略图
    ///   - videoURL: 视频网页的url地址
    public static func shareVideo(
        _ scence: WechatScene,
        title: String,
        description: String,
        thumbImage: UIImage? = nil,
        videoUrl: String
    ) {
        let object = WXVideoObject()
        object.videoUrl = videoUrl
        
        let message = getMediaMesage(title: "", description: "", thumbImage: thumbImage)
        message.mediaObject = object
        sendMediaMessage(scence: scence, message: message)
    }
    
    
    /// 分享 Emoticon
    /// - Parameters:
    ///   - scence: 请求发送场景
    ///   - emoticonData: 表情真实数据内容，大小不能超过10M
    ///   - thumbImage: 缩略图，大小不能超过256K
    public static func shareEmoticon(
        _ scence: WechatScene,
        emoticonData: Data,
        thumbImage: UIImage
    ) {
        let object = WXEmoticonObject()
        object.emoticonData = emoticonData
        
        let message = getMediaMesage(title: "", description: "", thumbImage: thumbImage)
        message.mediaObject = object
        sendMediaMessage(scence: scence, message: message)
    }
    
    
    /// 分享文件
    /// - Parameters:
    ///   - scence: 请求发送场景
    ///   - title: 标题
    ///   - description: 描述内容
    ///   - thumbImage: 缩略图
    ///   - fileData: 文件真实数据内容，大小不能超过10M
    ///   - fileExtension: 文件后缀名，长度不超过64字节
    public static func shareFile(
        _ scence: WechatScene,
        title: String,
        description: String,
        thumbImage: UIImage? = nil,
        fileData: Data,
        fileExtension: String
    ) {
        let object = WXFileObject()
        object.fileData = fileData
        object.fileExtension = fileExtension
        
        let message = getMediaMesage(title: title, description: description, thumbImage: thumbImage)
        message.mediaObject = object
        sendMediaMessage(scence: scence, message: message)
    }
    
    /// 拉起微信小程序
    /// - Parameters:
    ///   - userName: 小程序username
    ///   - path: 小程序的页面路径 (小程序页面路径；对于小游戏，可以只传入 query 部分，来实现传参效果，如：传入 "?foo=bar")
    ///   - miniProgramType: 小程序的类型，默认正式版，1.8.1及以上版本开发者工具包支持分享开发版和体验版小程序 (正式版: WXMiniProgramTypeRelease; 测试版: WXMiniProgramTypeTest; 体验版: WXMiniProgramTypePreview;)
    public static func launchMiniProgram(
        userName: String,
        path: String,
        miniProgramType: WXMiniProgramType
    ) {
        
        let req = WXLaunchMiniProgramReq()
        req.userName = userName
        req.path = path
        req.miniProgramType = miniProgramType
        
        WXApi.send(req)
    }
    
    
    /// 分享小程序
    /// - Parameters:
    ///   - scence: 请求发送场景
    ///   - title: 标题
    ///   - description: 描述内容
    ///   - thumbImage: 缩略图
    ///   - userName: 小程序username
    ///   - webpageUrl: 低版本网页链接，必须填写，否则拉不起来微信。
    ///   - path: 小程序的页面路径 (小程序页面路径；对于小游戏，可以只传入 query 部分，来实现传参效果，如：传入 "?foo=bar")
    ///   - miniProgramType: 小程序的类型，默认正式版，1.8.1及以上版本开发者工具包支持分享开发版和体验版小程序 (正式版: WXMiniProgramTypeRelease; 测试版: WXMiniProgramTypeTest; 体验版: WXMiniProgramTypePreview;)
    ///   - hdImageData: 小程序新版本的预览图二进制数据，6.5.9及以上版本微信客户端支持 (限制大小不超过128KB，自定义图片建议长宽比是 5:4。)
    ///   - withShareTicket: 是否使用带 shareTicket 的分享 (通常开发者希望分享出去的小程序被二次打开时可以获取到更多信息，例如群的标识。可以设置 withShareTicket 为true，当分享卡片在群聊中被其他用户打开时，可以获取到shareTicket，用于获取更多分享信息。)
    public static func shareMiniProgram(
        _ scence: WechatScene,
        title: String,
        description: String,
        thumbImage: UIImage? = nil,
        userName: String,
        webpageUrl: String,
        path: String,
        miniProgramType: WXMiniProgramType,
        hdImageData: Data,
        withShareTicket: Bool
    ) {
        
        let object = WXMiniProgramObject()
        object.userName = userName
        object.path = path
        object.webpageUrl = webpageUrl
        object.hdImageData = hdImageData
        object.withShareTicket = withShareTicket
        object.miniProgramType = miniProgramType
        
        let message = getMediaMesage(title: title, description: description, thumbImage: thumbImage)
        message.mediaObject = object
        
        sendMediaMessage(scence: scence, message: message)
    }
    
    
    /// 订阅小程序
    /// - Parameter miniProgramAppid: 小程序的appid
    public static func subscribeMiniProgram(_ miniProgramAppid: String) {
        let req = WXSubscribeMiniProgramMsgReq()
        req.miniProgramAppid = miniProgramAppid
        WXApi.send(req)
    }
    
    fileprivate static func getMediaMesage(
        title: String,
        description: String,
        thumbImage: UIImage?
    ) -> WXMediaMessage {
        
        let message = WXMediaMessage()
        
        /** 标题
         * @note 长度不能超过512字节
         */
        if title.count > 64 {
            let startIndex = title.startIndex
            let end = title.index(after: title.index(startIndex, offsetBy: 64))
            message.title = String(title[..<end])
        } else {
            message.title = title
        }
        
        /** 描述内容
         * @note 长度不能超过1K
         */
        if description.count > 128 {
            let startIndex = description.startIndex
            let end = description.index(after: description.index(startIndex, offsetBy: 128))
            
            message.description = String(description[..<end])
        } else {
            message.description = description
        }
        
        /** 缩略图数据
         * @note 大小不能超过256K
         */
        if let image = thumbImage, let data = image.compress(maxSize: 256*1024) {
            message.setThumbImage(UIImage(data: data)!)
        }
        
        return message
    }
    
    
    
    /// 获取多媒体消息结构体
    /// 用于微信终端和第三方程序之间传递消息的多媒体消息内容
    ///
    /// - Parameters:
    ///   - image: 需要分享的图片
    ///   - title: 标题
    ///   - description: 简介
    /// - Returns: 多媒体消息结构体
    fileprivate func getRequestMesage(
        _ image: UIImage?,
        title: String,
        description: String
    ) -> WXMediaMessage {
        
        let message = WXMediaMessage()
        /** 描述内容
         * @note 长度不能超过1K
         */
        if description.count > 128 {
            
            let startIndex = description.startIndex
            let end = description.index(after: description.index(startIndex, offsetBy: 128))
            
            message.description = String(description[..<end])
        } else {
            message.description = description
        }
        
        /** 缩略图数据
         * @note 大小不能超过64K
         */
        let thumbImage = image == nil ? UIImage() : self.resizeImage(image!, newWidth: 144)
        
        message.setThumbImage(thumbImage)
        
        /** 标题
         * @note 长度不能超过512字节
         */
        if title.count > 64 {
            
            let startIndex = title.startIndex
            let end = title.index(after: title.index(startIndex, offsetBy: 64))
            
            message.title = String(title[..<end])
        } else {
            message.title = title
        }
        
        return message
    }
    
    /// 重置图片大小
    ///
    /// - Parameters:
    ///   - image: 图片
    ///   - newWidth: 目标宽度
    /// - Returns: 重置后的图片
    fileprivate func resizeImage(_ image: UIImage, newWidth: CGFloat) -> UIImage {
        
        let newHeight = image.size.height / image.size.width * newWidth
        UIGraphicsBeginImageContext( CGSize(width: newWidth, height: newHeight) )
        image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return newImage!
    }
    
    /// 送请求到微信，等待微信返回onResp
    /// 函数调用后，会切换到微信的界面。
    /// 第三方应用程序等待微信返回onResp。
    /// 微信在异步处理完成后一定会调用onResp。
    ///
    /// - Parameters:
    ///   - message: message description
    ///   - scence: scence description
    ///   - bText: true: 文本消息， false: 多媒体消息
    fileprivate func sendReq(bText: Bool, message: WXMediaMessage, scence: WechatScene) {
        let req = SendMessageToWXReq()
        req.bText = bText
        req.message = message
        req.scene = Int32(scence.rawValue)
        
        WXApi.send(req)
    }
    
    fileprivate static func sendMediaMessage(scence: WechatScene, message: WXMediaMessage) {
        let req = SendMessageToWXReq()
        req.bText = false
        req.message = message
        req.scene = Int32(scence.rawValue)
        
        WXApi.send(req)
    }
    
}

// MARK: - 支付
extension WechatManager {
    /// 微信支付
    /// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_4.shtml
    /// - Parameter payReq: 发送请求信息到微信，等待微信返回onResp
    func pay(payReq: WechatPayReq) {
        let req = PayReq()
        // 由用户微信号和AppID组成的唯一标识，用于校验微信用户
        req.openID = payReq.appid
        // 商家向财付通申请的商家id
        req.partnerId = payReq.partnerid
        // 预支付订单这个是后台跟微信服务器交互后，微信服务器传给你们服务器的，你们服务器再传给你
        req.prepayId = payReq.prepayid
        // 随机串，防重发
        req.nonceStr = payReq.noncestr
        // 时间戳，防重发
        req.timeStamp = payReq.timestamp
        // 商家根据财付通文档填写的数据和签名
        req.package = payReq.package
        // 商家根据微信开放平台文档对数据做的签名
        req.sign = payReq.sign
        // 发送请求到微信，等待微信返回onResp
        WXApi.send(req)
    }
    
}

extension WechatManager: WXApiDelegate {
    
    // 是微信终端向第三方程序发起请求，要求第三方程序响应。第三方程序响应完后必须调用 sendRsp 返回。在调用 sendRsp 返回时，会切回到微信终端程序界面。
    func onReq(_ req: BaseReq) {
        if let wxReq = req as? PayReq {
            xLog("[微信] onReq PayReq 支付 \(wxReq)")
        } else if let wxReq = req as? WXOfflinePayReq {
            xLog("[微信] onReq WXOfflinePayReq 离线支付 \(wxReq)")
        } else if let wxReq = req as? WXNontaxPayReq {
            xLog("[微信] onReq WXNontaxPayReq 调用非税支付 \(wxReq)")
        } else if let wxReq = req as? WXPayInsuranceReq {
            xLog("[微信] onReq WXPayInsuranceReq 医保支付 \(wxReq)")
        } else if let wxReq = req as? SendAuthReq {
            xLog("[微信] onReq SendAuthReq \(wxReq)")
        } else if let wxReq = req as? SendMessageToWXReq {
            xLog("[微信] onReq SendMessageToWXReq \(wxReq)")
        } else if let wxReq = req as? GetMessageFromWXReq {
            xLog("[微信] onReq GetMessageFromWXReq \(wxReq)")
        } else if let wxReq = req as? ShowMessageFromWXReq {
            xLog("[微信] onReq ShowMessageFromWXReq \(wxReq)")
        } else if let wxReq = req as? LaunchFromWXReq {
            xLog("[微信] onReq LaunchFromWXReq \(wxReq)")
        } else {
            xLog("[微信] onReq \(req)")
        }
    }
    
    // 如果第三方程序向微信发送了 sendReq 的请求，那么 onResp 会被回调。sendReq 请求调用后，会切到微信终端程序界面。
    func onResp(_ resp: BaseResp) {
        
        if let wxResp = resp as? PayResp {
            //0    成功    展示页面成功
            //-1    错误    可能的原因：签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常原因等
            //-2    用户取消    无需处理。发生场景：用户不支付了，点击取消，返回APP
            xLog("[微信] onResp SendAuthResp \(wxResp.errCode)")
            delegate?.wechatPayResp?(code: WechatResultCode(rawValue: wxResp.errCode)!, errMsg: wxResp.errStr)
            
        } else if let wxResp = resp as? WXOfflinePayResp {
            xLog("[微信] onResp WXOfflinePayResp \(wxResp)")
        } else if let wxResp = resp as? WXNontaxPayResp {
            xLog("[微信] onResp WXNontaxPayResp \(wxResp)")
        } else if let wxResp = resp as? WXPayInsuranceResp {
            xLog("[微信] onResp WXPayInsuranceResp \(wxResp)")
        } else if let wxResp = resp as? SendAuthResp {
            // ERR_OK = 0(用户同意) ERR_AUTH_DENIED = -4（用户拒绝授权） ERR_USER_CANCEL = -2（用户取消）
            // 用户换取 access_token 的 code，仅在 ErrCode 为 0 时有效
            xLog("[微信] onResp errCode:\(wxResp.errCode)  code:\(wxResp.code ?? "kong")")
            delegate?.wechatAuthResp?(code: wxResp.code, errCode: WechatResultCode(rawValue: wxResp.errCode) ?? WechatResultCode.common)
            
        } else if let wxResp = resp as? SendMessageToWXResp {
            xLog("[微信] onResp SendMessageToWXResp \(wxResp.description)")
            delegate?.wechatShareResp?()
        } else if let wxResp = resp as? GetMessageFromWXResp {
            xLog("[微信] onResp GetMessageFromWXResp \(wxResp)")
        } else if let wxResp = resp as? ShowMessageFromWXResp {
            xLog("[微信] onResp ShowMessageFromWXResp \(wxResp)")
        } else {
            xLog("[微信] onResp \(resp)")
        }
    }
}
